package com.gagakuai.app.rvm;

import com.gagakuai.domain.actions.Action;
import com.gagakuai.domain.engines.RuleEngine;
import com.gagakuai.domain.events.ExecuteAfterEvent;
import com.gagakuai.domain.events.ExecuteBeforeEvent;
import com.gagakuai.domain.facts.Facts;
import com.gagakuai.domain.jude.RuleJudeExecutor;
import com.gagakuai.domain.rules.Rule;
import com.gagakuai.domain.rules.Rules;
import com.gagakuai.infrastructure.utils.SpringContextHolder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @description: 默认执行器
 * @author: houhong
 * @create: 2024-09-07 10:55
 **/

@Component
public class DafalutRuleEngine implements RuleEngine, SmartInitializingSingleton {

    public static final Logger LOGGER = LoggerFactory.getLogger(DafalutRuleEngine.class);

    @Autowired
    List<RuleJudeExecutor> ruleJudeExecutors;

    private Map<Integer, RuleJudeExecutor> ruleJudeExecutorMap = new HashMap<>();


    @Override
    public void execute(Rules rules, Facts facts) {

        Objects.requireNonNull(rules, "rules must not be null");
        Objects.requireNonNull(facts, "facts must not be null");

        ExecuteBeforeEvent beforeEvent = new ExecuteBeforeEvent(rules);
        SpringContextHolder.publish(beforeEvent);

        doExecute(rules, facts);

        ExecuteAfterEvent afterEvent = new ExecuteAfterEvent(rules);
        SpringContextHolder.publish(afterEvent);

    }

    private void doExecute(Rules rules, Facts facts) {

        for (Rule rule : rules) {

            boolean hint = evacuate(rule, facts);
            if (!hint) {
                LOGGER.debug("规则未命中!{}-facts:{}", rule,facts);
                continue;
            }
            //执行后续action
            execute(rule, facts);
        }

    }

    /*
     * 规则判断
     */
    private boolean evacuate(Rule rule, Facts facts) {

        //规则类型
        Integer type = rule.getType();

        if (type == null) {
            LOGGER.error("规则类型不能为空干!{}", rule);
            throw new RuntimeException();
        }

        RuleJudeExecutor judeExecutor = ruleJudeExecutorMap.get(type);
        if (judeExecutor == null) {
            LOGGER.error("当前规则类型： {},无对应的规则执行器，请检查!!", type);
            throw new RuntimeException();
        }
        return judeExecutor.execute(rule, facts);

    }

    private void execute(Rule rule, Facts facts) {

        final List<Action> actions = rule.getActions();
        if (CollectionUtils.isEmpty(actions)) return;
        actions.forEach(action -> action.execute(facts));
    }

    @Override
    public void afterSingletonsInstantiated() {

        if (CollectionUtils.isEmpty(ruleJudeExecutors)) return;

        ruleJudeExecutorMap = ruleJudeExecutors.stream()
                .collect(Collectors.toMap(RuleJudeExecutor::getType, executor -> executor));

    }
}
